#include "worksheet.h"
#include "eval_proc.h"

addressO AlokasiOri ()
/* Mengalokasikan memori untuk Origin */
{
	addressO temp = Nil;
	temp =(addressO)malloc(sizeof(Origin));
	
	if (temp != Nil)
	{
		NextColOri(temp) = Nil;
		NextBrsOri(temp) = Nil;
	}
	
	return (temp);
}

addressC AlokasiHC (string Info)
/* Mengalokasikan memori untuk satu elemen pada Header Column */
{
	addressC temp = Nil;
	temp =(addressC)malloc(sizeof(HeaderColumn));
	
	if (temp != Nil)
	{
		NextHC(temp) = Nil;
		FirstCol(temp) = Nil;
		InfoCol(temp) = Info;
	}
	
	return (temp);
}

addressR AlokasiHR (int Info)
/* Mengalokasikan memori untuk satu elemen pada Header Baris */
{
	addressR temp = Nil;
	temp =(addressR)malloc(sizeof(HeaderRow));
	
	if (temp != Nil)
	{
		NextHR(temp) = Nil;
		FirstBrs(temp) = Nil;
		InfoBrs(temp) = Info;
	}
	
	return (temp);
}

address AlokasiCell (string Info)
/* Mengalokasikan memori untuk satu cell pada Spreadsheet */
{
	address temp = Nil;
	temp =(address)malloc(sizeof(Cell));
	
	if (temp != Nil)
	{
		NextCol(temp) = Nil;
		NextBrs(temp) = Nil;
		AdrBrs(temp) = 0;
		InfoType(temp) = 0;
		InfoChar(temp) = Info;
		InfoInt(temp) = 0;
		InfoDouble(temp) = 0;
		InfoBoolean(temp) = false;
	}
	
	return (temp);
}

void DealokasiO (addressO *P)
/* Mendealokasikan memori yang teralokasi untuk origin */
{
	free(*P);
}

void DealokasiHR (addressR *P)
/* Mendealokasikan memori yang teralokasi untuk satu elemen pada Header Row */
{
	free(*P);
}

void DealokasiHC (addressC *P)
/* Mendealokasikan memori yang teralokasi untuk satu elemen pada Header Column */
{
	free(*P);
}

void DealokasiC (address *P)
/* Mendealokasikan memori yang teralokasi untuk satu Cell pada Spreadsheet*/
{
	free(*P);
}

boolean IsEmptySheet (Sheet S)
/* Mengecek apakah sheet kosong dengan parameter NextHeaderColomn dan NextHeaderRow bernilai Nil */
{
	return ((NextBrsOri(S) == Nil) && (NextColOri(S) == Nil));
}

void CreateEmpty (Sheet *S)
/* Membuat sheet yang kosong yaitu terbentuk Origin dengan NextHeaderColomn dan NextHeaderRow bernilai Nil */
{
	(*S) = AlokasiOri();
}

void InsertXY (Sheet *S, string Pos, string Isi)
/* Menambahkan satu cell pada Spreadsheet dengan elemen berupa Isi pada posisi (Column,Row) */
{
	address P, PTemp, Prec;
	addressR Pr, PTempR, PrecR;
	addressC Pc, PTempC, PrecC;
	string Column;
	int Row;
	boolean Found;
	
	PosToCR(Pos,&Column,&Row);
		
	P = AlokasiCell(Isi);
	if (P != Nil)
	{
		AdrBrs(P) = Row;
		AdrCol(P) = Column;
		
		//do
		//{
			InfoChar(P) = Isi;
			if (IsStringInteger(Isi))
			{
				InfoType(P) = 1;
			}
			else if (IsStringDouble(Isi))
			{
				InfoType(P) = 2;
			}
			else if (IsStringFormula(Isi))
			{
				InfoType(P) = 5;
			}
			else if (IsStringBoolean(Isi))
			{
				InfoType(P) = 3;
			}
			else
			{
				InfoType(P) = 4;
			}
		//} while (InfoType(P) == 5);

	Pr = AlokasiHR(Row);
	Pc = AlokasiHC(Column);

	if (IsEmptySheet(*S))
	{
		NextColOri(*S) = Pc;
		NextBrsOri(*S) = Pr;
		FirstCol(Pc) = P;
		FirstBrs(Pr) = P;
	}
	else
	{
		PTempC = NextColOri(*S);
		PrecC = Nil;

		do
		{
			if (IsStringEq(Column,InfoCol(PTempC)))
			{
				PTemp = FirstCol(PTempC);
				Prec = Nil;
				Found = false;
	
				while ((NextBrs(PTemp) != Nil) && (!Found))
				{
					if (AdrBrs(PTemp) < Row)
					{
						Prec = PTemp;
						PTemp = NextBrs(PTemp);
						
					}
					else
					{
						Found = true;
					}
				}

				if ((Prec == Nil) && (Row < AdrBrs(PTemp)))
				{
					NextBrs(P) = PTemp;
					FirstCol(PTempC) = P;
				}
				else if ((NextBrs(PTemp) == Nil) && (AdrBrs(PTemp) < Row))
				{
					NextBrs(PTemp) = P;
				}
				else
				{
					NextBrs(P) = NextBrs(Prec);
					NextBrs(Prec) = P;
				}
				PTempC = Nil;
			}
			else if (IsStringLt(InfoCol(PTempC),Column))
			{
				PrecC = PTempC;
				PTempC = NextHC(PTempC);
				if (PTempC == Nil)
				{
					NextHC(PrecC) = Pc;
					FirstCol(Pc) = P;
					NextHC(Pc) = Nil;
				}
			}
			else
			{
				if (PrecC == Nil)
				{
					NextHC(Pc) = PTempC;
					NextColOri(*S) = Pc;
				}
				else
				{
					NextHC(Pc) = NextHC(PrecC);
					NextHC(PrecC) = Pc;
				}
				FirstCol(Pc) = P;
				PTempC = Nil;
			}
		} while (PTempC != Nil);

		PTempR = NextBrsOri(*S);
		PrecR = Nil;
		do
		{
			if (Row == InfoBrs(PTempR))
			{
				PTemp = FirstBrs(PTempR);
				Prec = Nil;
				Found = false;
				while ((NextCol(PTemp) != Nil) && (!Found))
				{					
					if (IsStringLt(AdrCol(PTemp),Column))
					{
						Prec = PTemp;
						PTemp = NextCol(PTemp);
					}
					else
					{
						Found = true;
					}
				}

				if (IsStringEq(Column,AdrCol(PTemp)))
				{
					InfoChar(PTemp) = Isi;
				}
				else
				{
					if ((Prec == Nil) && (IsStringLt(Column,AdrCol(PTemp))))
					{
						NextCol(P) = PTemp;
						FirstBrs(PTempR) = P;
					}
					else if ((NextCol(PTemp) == Nil) && (IsStringLt(AdrCol(PTemp),Column)))
					{
						NextCol(PTemp) = P;
					}
					else
					{
						NextCol(P) = NextCol(Prec);
						NextCol(Prec) = P;
					}
				}
				PTempR = Nil;
			}
			else if (InfoBrs(PTempR) < Row)
			{
				PrecR = PTempR;
				PTempR = NextHR(PTempR);
				if (PTempR == Nil)
				{
					NextHR(PrecR) = Pr;
					FirstBrs(Pr) = P;
					NextHR(Pr) = Nil;
				}
			}
			else
			{
				if (PrecR == Nil)
				{
					NextHR(Pr) = PTempR;
					NextBrsOri(*S) = Pr;
				}
				else
				{
					NextHR(Pr) = NextHR(PrecR);
					NextHR(PrecR) = Pr;
				}
				FirstBrs(Pr) = P;
				PTempR = Nil;
			}
		} while (PTempR != Nil);	
	}
	}
}

void GetXY (Sheet S, string Pos, address *Isi)
/* Mengambil alamat dari satu cell pada Spreadsheet dengan elemen berupa Isi pada posisi (Column,Row) */
{
	addressR Pr;
	address P;
	boolean Found;
	string Column;
	int Row;
	
	PosToCR(Pos,&Column,&Row);
	
	Pr = NextBrsOri(S);
	Found = false;
	while ((Pr != Nil) && (!Found))
	{
		if (InfoBrs(Pr) != Row)
		{
			Pr = NextHR(Pr);
		}
		else
		{
			Found = true;
		}
	}
	
	if (Pr != Nil)
	{
		P = FirstBrs(Pr);
		Found = false;
		while ((P != Nil) && (!Found))
		{
			if (!IsStringEq(AdrCol(P),Column))
			{
				P = NextCol(P);
			}
			else
			{
				Found = true;
			}
		}
		(*Isi) = P;
	}
	else
	{
		(*Isi) = Nil;
	}
}

void GetXYChar (Sheet S, string Pos, string *Isi)
/* Mengambil nilai pada sel dengan posisi (Column,Row) dalam tipe string */
{
	addressR Pr;
	address P;
	boolean Found;
	int Row;
	string Column;
	
	PosToCR(Pos,&Column,&Row);
	if ((Row > 0)&&(StringToBool(GT(Column,CharToString("A"))))) {
	Pr = NextBrsOri(S);
	Found = false;
	while ((Pr != Nil) && (!Found))
	{
		if (InfoBrs(Pr) != Row)
		{
			Pr = NextHR(Pr);
		}
		else
		{
			Found = true;
		}
	}
	
	if (Pr != Nil)
	{
		P = FirstBrs(Pr);
		Found = false;
		while ((P != Nil) && (!Found))
		{
			if (!IsStringEq(AdrCol(P),Column))
			{
				P = NextCol(P);
			}
			else
			{
				Found = true;
			}
		}
		if (P != Nil)
		{
			(*Isi) = InfoChar(P);
		}
		else
		{
			(*Isi).s[0] = '\0';
			(*Isi).length = 0;
		}
	}
	else
	{
		(*Isi).s[0] = '\0';
		(*Isi).length = 0;
	}}else *Isi = CharToString("ERROR");
}
	

void DeleteXY (Sheet *S, string Pos)
/* Menghapus satu cell pada Spreadsheet pada posisi (Column,Row) */
{
	addressR Pr, PrecR;
	address P, Prec;
	addressC Pc, PrecC;
	int Row;
	string Column;
	boolean Found;
	
	PosToCR(Pos,&Column,&Row);

	Pr = NextBrsOri(*S);
	PrecR = Nil;
	Found = false;
	while ((Pr != Nil) && (!Found))
	{
		if (InfoBrs(Pr) != Row)
		{
			PrecR = Pr;
			Pr = NextHR(Pr);
		}
		else
		{
			Found = true;
		}
	}
	
	if (Pr != Nil)
	{
		P = FirstBrs(Pr);
		Prec = Nil;
		Found = false;
		while ((P != Nil) && (!Found))
		{
			if (!IsStringEq(AdrCol(P),Column))
			{
				Prec = P;
				P = NextCol(P);
			}
			else
			{
				Found = true;
			}
		}
		
		if (P != Nil)
		{
			if (Prec == Nil)
			{
				FirstBrs(Pr) = NextCol(P);
			}
			else
			{
				NextCol(Prec) = NextCol(NextCol(Prec));	
			}
			NextCol(P) = Nil;
	
			if (FirstBrs(Pr) == Nil)
			{
				if (PrecR == Nil)
				{
					NextBrsOri(*S) = NextHR(Pr);
				}
				else
				{
					NextHR(PrecR) = NextHR(NextHR(PrecR));
				}
				NextHR(Pr) = Nil;
				DealokasiHR(&Pr);
			}
		}
	}

	Pc = NextColOri(*S);
	PrecC = Nil;
	Found = false;
	while ((Pc != Nil) && (!Found))
	{
		if (!IsStringEq(InfoCol(Pc),Column))
		{
			PrecC = Pc;
			Pc = NextHC(Pc);
		}
		else
		{
			Found = true;
		}
	}
	
	if (Pc != Nil)
	{
		P = FirstCol(Pc);
		Prec = Nil;
		Found = false;
		while ((P != Nil) && (!Found))
		{
			if (AdrBrs(P) != Row)
			{
				Prec = P;
				P = NextBrs(P);
			}
			else
			{
				Found = true;
			}
		}
		
		if (P != Nil)
		{
			if (Prec == Nil)
			{
				FirstCol(Pc) = NextBrs(P);
			}
			else
			{
				NextBrs(Prec) = NextBrs(NextBrs(Prec));	
			}
			NextBrs(P) = Nil;
			DealokasiC(&P);

			if (FirstCol(Pc) == Nil)
			{
				if (PrecC == Nil)
				{
					NextColOri(*S) = NextHC(Pc);
				}
				else
				{
					NextHC(PrecC) = NextHC(NextHC(PrecC));
				}	
				NextHC(Pc) = Nil;
				DealokasiHC(&Pc);
			}
		}
	}
}

void RemoveArea (Sheet *S, string PosStart, string PosEnd)
{
	string s, ColAw, ColAk, Pos;
	int i, RowAw, RowAk;
	
	PosToCR(PosStart,&ColAw,&RowAw);
	PosToCR(PosEnd,&ColAk,&RowAk);

	for (i = RowAw; i <= RowAk; i++)
	{
		s = ColAw;
		while ((!IsStringLt(ColAk,s)) || (IsStringEq(ColAk,s)))
		{
			CRToPos(s,i,&Pos);
			DeleteXY(S,Pos);
			NextAlfa(&s);
		}
	}
}

void DeleteAll (Sheet *S)
/* Menghapus semua sel yang ada dalam spreadsheet */
{
	addressR Pr;
	addressC Pc;
	address P;
	
	Pr = NextBrsOri(*S);
	while (Pr != Nil)
	{
		P = FirstBrs(Pr);
		while (P != Nil)
		{
			FirstBrs(Pr) = NextCol(P);
			NextCol(P) = Nil;
			P = FirstBrs(Pr);
		}
		NextBrsOri(*S) = NextHR(Pr);
		NextHR(Pr) = Nil;
		DealokasiHR(&Pr);
		Pr = NextBrsOri(*S);
	}
	
	Pc = NextColOri(*S);
	while (Pc != Nil)
	{
		P = FirstCol(Pc);
		while (P != Nil)
		{
			FirstCol(Pc) = NextBrs(P);
			NextBrs(P) = Nil;
			DealokasiC(&P);
			P = FirstCol(Pc);
		}
		NextColOri(*S) = NextHC(Pc);
		NextHC(Pc) = Nil;
		DealokasiHC(&Pc);
		Pc = NextColOri(*S);
	}
}

void MaxIndex (Sheet S, string *MaxIdx)
{
	addressR Pr;
	addressC Pc;
	int Row;
	string Column;
	
	Pr = NextBrsOri(S);
	if (Pr == Nil)
	{
		Row = 1;
	}
	else
	{
		while (NextHR(Pr) != Nil)
		{
			Pr = NextHR(Pr);
		}
		Row = InfoBrs(Pr);
	}
	
	Pc = NextColOri(S);
	if (Pc == Nil)
	{
		Column.s[0] = 'A';
		Column.s[1] = '\0';
		Column.length = 1;
	}
	else
	{
		while (NextHC(Pc) != Nil)
		{
			Pc = NextHC(Pc);
		}
		Column = InfoCol(Pc);
	}
	
	CRToPos(Column,Row,MaxIdx);
}

void PrintInfoType (address Isi)
/* Menampilkan info dari sel dengan berbagai kemungkinan yang ada */
{
	printf("%s",InfoChar(Isi).s);
}
